using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.Universal;


namespace CNGraphi.U6URP
{
    /// <summary>
    /// 双边滤波降噪
    /// <para>作者：CN.Graphi</para>
    /// </summary>
    [VolumeComponentMenu("G Post-processing/Blur/Bilateral Filter")]
    public class BilateralFilter : GPostProcess
    {
        #region 参数
        public MinIntParameter Iteration = new MinIntParameter(1, 1, true);
        public ClampedFloatParameter Weight = new ClampedFloatParameter(0.8f, 0.0f, 1.0f, true);
        public MinFloatParameter Intensity = new MinFloatParameter(0.0f, 0.0f, true);
        #endregion


        TextureHandle temp0;
        TextureHandle temp1;


        public override bool IsActive() => mMaterial != null && Intensity.value != 0.0f;


        internal override void OnTextureCreate(RenderGraph renderGraph, ContextContainer frameData)
        {
            if (mMaterial == null) { return; }

            UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
            var desc = cameraData.cameraTargetDescriptor;
            desc.depthBufferBits = 0;

            temp0 = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, "BilateralFilter_Temp0", false, FilterMode.Bilinear, TextureWrapMode.Clamp);
            temp1 = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, "BilateralFilter_Temp1", false, FilterMode.Bilinear, TextureWrapMode.Clamp);
        }

        internal override void OnTextureUseCommit(IUnsafeRenderGraphBuilder builder)
        {
            if (mMaterial == null) { return; }

            builder.UseTexture(temp0);
            builder.UseTexture(temp1);
        }

        internal override void OnRender(CommandBuffer cmd, PostProcessPassData passData, TextureHandle src, TextureHandle dst)
        {
            if (mMaterial == null) { return; }

            Draw(cmd, src, temp0);

            mMaterial.SetFloat("_Weight", Weight.value);
            for (int i = 0; i < Iteration.value; i++)
            {
                mMaterial.SetFloat("_Intensity", Intensity.value * (i + 1));
                // 横向
                Draw(cmd, temp0, temp1, 0);
                CoreUtils.Swap(ref temp0, ref temp1);
                // 纵向
                Draw(cmd, temp0, temp1, 1);
                CoreUtils.Swap(ref temp0, ref temp1);
            }

            Draw(cmd, temp0, dst);
        }

        protected override void OnDispose()
        {
        }
        
    }
}